/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Cobalt.Framework.Graphics
{
	public abstract class GeometrySource
	{
		/// <summary>
		/// Draws the geometry surfaces in the specified range.
		/// </summary>
		/// <remarks>
		/// All of the surfaces in the subrange are
		/// guaranteed to belong to this object.
		/// </remarks>
		/// <param name="surfaces">The array of surfaces to draw.</param>
		/// <param name="index">The index of the first surface to draw.</param>
		/// <param name="count">The number of surfaces to draw.</param>
		/// <param name="context">The current shading context.</param>
		protected internal abstract void DrawSurfaces( DrawRecord[] surfaces,
			int index, int count, ShadingContext context, IPrerenderHandler prerenderHandler );

		/// <summary>
		/// Called before any surfaces are drawn.
		/// </summary>
		/// <param name="context">The context the source will draw to.</param>
		/// <remarks>
		/// Note that there may be several calls to <see cref="DrawSurfaces"/>
		/// between calls to <c>Begin</c> and <see cref="End"/>, each potentially using
		/// different materials.
		/// 
		/// Overriders need not call the base method.
		/// </remarks>
		protected internal virtual void Begin( ShadingContext context, IPrerenderHandler prerenderHandler ) { }
		/// <summary>
		/// Called when the current batch of surfaces has been drawn.
		/// </summary>
		/// <param name="context">The context the source drew to.</param>
		/// <remarks>
		/// Overriders need not call the base method.
		/// </remarks>
		protected internal virtual void End( ShadingContext context, IPrerenderHandler prerenderHandler ) { }

		protected internal interface IPrerenderHandler
		{
			/// <summary>
			/// Called before a bracket of Prerender calls.
			/// </summary>
			/// <param name="source">The <see cref="GeometrySource"/> beging pre-rendered.</param>
			void BeginPrerender( GeometrySource source );
			/// <summary>
			/// Called to pre-render a batch of geometry.
			/// </summary>
			/// <param name="source">The <see cref="GeometrySource"/> to be pre-rendered.</param>
			/// <param name="surfaces">The array of surfaces to pre-render.</param>
			/// <param name="index">The first surface to pre-render.</param>
			/// <param name="count">The number of surfaces to pre-render.</param>
			/// <param name="context">The shading context for pre-rendering.</param>
			void Prerender( GeometrySource source, DrawRecord[] surfaces, int index, int count, ShadingContext context );
			/// <summary>
			/// Called after a bracket of Prerender calls.
			/// </summary>
			/// <param name="source">The <see cref="GeometrySource"/> beging pre-rendered.</param>
			void EndPreRender( GeometrySource source );
		}

		/// <summary>
		/// Sets up a new pre-render handler for the geometry source.
		/// </summary>
		/// <returns>A pre-render handler for the geometry source.</returns>
		/// <remarks>
		/// Return null if this source doesn't need a pre-render helper. By default
		/// this method returns null.
		/// </remarks>
		protected internal virtual IPrerenderHandler CreatePrerenderHandler()
		{
			return null;
		}

		private static int nextSortId;

		internal int sortId;
		protected GeometrySource()
		{
			sortId = nextSortId++;
		}
	}

	public abstract class GeometrySurface
	{
		internal GeometrySource source;
		protected GeometrySurface( GeometrySource source )
		{
			this.source = source;
		}

		public GeometrySource Source
		{
			get { return source; }
		}

		internal int surfaceSort;
		public int SurfaceSort
		{
			get { return surfaceSort; }
			protected set { surfaceSort = value; }
		}

		internal Vector3 center;
		public Vector3 Center
		{
			get { return center; }
			protected set { center = value; }
		}
	}
}
